#include <iostream>
#include <string>
#include <string.h>
#include <strings.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <unordered_map>

#include "httpTool.hpp"

using namespace httptool;

#define READSIZE 4096

uint16_t defaultport = 8080;
static std::string defaultip = "0.0.0.0";
static const int gbacklog = 5;

namespace calServer
{
    class Server;

    typedef void(*fun_t)(Request&,Responce& resp);
    class Context
    {
    public:
        Context(Server *server, int socket) : _server(server), _socket(socket)
        {
        }

        Server *_server;
        int _socket;
    };

    class Server
    {
    public:
        Server(const uint16_t &Serverport = defaultport, const std::string &Serverip = defaultip)
            : _Serverport(Serverport), _Serverip(Serverip), _sockfd(-1),_funt(responceMessage)
        {
        }

        void init()
        {
            // 穿件套接字，打开文件描述符
            _sockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd == -1)
            {
                // 打印错误日志，返回
                exit(1);
            }
            // 打印成功日志

            // 开始建立bind链接
            struct sockaddr_in address;
            bzero(&address, sizeof(address));
            address.sin_family = AF_INET;
            address.sin_port = htons(_Serverport);
            address.sin_addr.s_addr = INADDR_ANY;

            int n = bind(_sockfd, (struct sockaddr *)&address, sizeof(address));
            if (n == -1)
            {
                exit(2);
            }

            // 开始监听

            n = listen(_sockfd, gbacklog);
            if (n < 0)
            {
                exit(3);
            }
        }

        void start()
        {

            while (1)
            {
                struct sockaddr_in address;
                bzero(&address, sizeof(address));
                socklen_t length = sizeof(address);
                int sock = accept(_sockfd, (struct sockaddr *)&address, &length);

                if (sock == -1)
                {
                    std::cout << "本次获取链接失败" << std::endl;
                    continue;
                }
                //std::cout << "socketfd :" << sock << std::endl;

                pthread_t tid;
                Context *ctx = new Context(this, sock);
                pthread_create(&tid, nullptr, provideServer, (void *)ctx);
                // 线程可不敢乱关文件描述符，因为是公用一套的
            }
        }

        static void serverio(Context* ctx)
        {
            //保证读到http完整的信息
            // 有两个结构体，一个接受，一个回复
            // 序列化和反序列化的工作
            // 开始了，先接收流量器的请求
            char buffer[READSIZE];
            Responce resp;Request req; 

            ssize_t n = recv(ctx->_socket,buffer,sizeof buffer - 1 , 0);  //大概率就可以读完请求
            if(n > 0)
            {
                buffer[n] = 0;
                req._reqBuffer = buffer;  
                //std::cout << req._reqBuffer << std::endl;
                
                if(req.getandsubstrline()) ;
            
                ctx->_server->_funt(req,resp);
                //std::cout << resp._respBuffer << std::endl;
                ssize_t n = send(ctx->_socket,resp._respBuffer.c_str(),resp._respBuffer.size(),0);
                if( n <= 0)
                    std::cout << "web退出接收,me too!" << std::endl;
            }

        }

        static void *provideServer(void *arvg)
        {
            pthread_detach(pthread_self());
            Context *ctx = static_cast<Context *>(arvg);
            // 执行服务
            ctx->_server->serverio(ctx);
            //serverio(ctx->_socket);
            // 执行完成后，释放文件描述符,并且释放被new出来了的 ctx
            close(ctx->_socket);
            delete ctx;
        }

    private:
        std::string _Serverip;
        uint16_t _Serverport;
        int _sockfd;
        fun_t _funt;
        //以路径来标识服务
        //std::unordered_map<std::string,fun_t> Task;
    };
}